/*
http://www.cgsoso.com/forum-211-1.html

CG搜搜 Unity3d 每日Unity3d插件免费更新 更有VIP资源！

CGSOSO 主打游戏开发，影视设计等CG资源素材。

插件如若商用，请务必官网购买！

daily assets update for try.

U should buy the asset from home store if u use it in your project!
*/

using System;
using System.Collections.Generic;

using UnityEngine;
using BestHTTP;

public sealed class LargeFileDownloadSample : MonoBehaviour
{
    /// <summary>
    /// The url of the resource to download
    /// </summary>
    const string URL = "http://ipv4.download.thinkbroadband.com/100MB.zip";

    #region Private Fields

    /// <summary>
    /// Cached request to be able to abort it
    /// </summary>
    HTTPRequest request;

    /// <summary>
    /// Debug status of the request
    /// </summary>
    string status = string.Empty;

    /// <summary>
    /// Download(processing) progress. Its range is between [0..1]
    /// </summary>
    float progress;

    /// <summary>
    /// The fragment size that we will set to the request
    /// </summary>
    int fragmentSize = HTTPResponse.MinBufferSize;

    #endregion

    #region Unity Events

    void Awake()
    {
        // If we have a non-finished download, set the progress to the value where we left it
        if (PlayerPrefs.HasKey("DownloadLength"))
            progress = PlayerPrefs.GetInt("DownloadProgress") / (float)PlayerPrefs.GetInt("DownloadLength");
    }

    void OnDestroy()
    {
        // Stop the download if we are leaving this example
        if (request != null && request.State < HTTPRequestStates.Finished)
        {
            request.OnProgress = null;
            request.Callback = null;
            request.Abort();
        }
    }

    void OnGUI()
    {
        GUIHelper.DrawArea(GUIHelper.ClientArea, true, () =>
            {
                // Draw the current status
                GUILayout.Label("Request status: " + status);

                GUILayout.Space(5);

                // Draw the current progress
                GUILayout.Label(string.Format("Progress: {0:P2} of {1:N0}Mb", progress, PlayerPrefs.GetInt("DownloadLength") / 1048576 /*1 Mb*/));
                GUILayout.HorizontalSlider(progress, 0, 1);

                GUILayout.Space(50);

                if (request == null)
                {
                    // Draw a slider to be able to change the fragment size
                    GUILayout.Label(string.Format("Desired Fragment Size: {0:N} KBytes", fragmentSize / 1024f));
                    fragmentSize = (int)GUILayout.HorizontalSlider(fragmentSize, HTTPResponse.MinBufferSize, 10 * 1024 * 1024);

                    GUILayout.Space(5);

                    string buttonStr = PlayerPrefs.HasKey("DownloadProgress") ? "Continue Download" : "Start Download";
                    if (GUILayout.Button(buttonStr))
                        StreamLargeFileTest();
                }
                else if (request.State == HTTPRequestStates.Processing && GUILayout.Button("Abort Download"))
                {
                    // Simulate a connection lost
                    request.Abort();
                }
            });
    }

    #endregion

    #region Private Helper Functions

    // Calling this function again when the "DownloadProgress" key in the PlayerPrefs present will 
    //	continue the download
    void StreamLargeFileTest()
    {
        request = new HTTPRequest(new Uri(URL), (req, resp) =>
        {
            switch (req.State)
            {
                // The request is currently processed. With UseStreaming == true, we can get the streamed fragments here
                case HTTPRequestStates.Processing:

                    // Set the DownloadLength, so we can display the progress
                    if (!PlayerPrefs.HasKey("DownloadLength"))
                    {
                        string value = resp.GetFirstHeaderValue("content-length");
                        if (!string.IsNullOrEmpty(value))
                            PlayerPrefs.SetInt("DownloadLength", int.Parse(value));
                    }

                    // Get the fragments, and save them
                    ProcessFragments(resp.GetStreamedFragments());

                    status = "Processing";
                    break;

                // The request finished without any problem.
                case HTTPRequestStates.Finished:
                    if (resp.IsSuccess)
                    {
                        // Save any remaining fragments
                        ProcessFragments(resp.GetStreamedFragments());

                        // Completly finished
                        if (resp.IsStreamingFinished)
                        {
                            status = "Streaming finished!";

                            // We are done, delete the progress key
                            PlayerPrefs.DeleteKey("DownloadProgress");
                            PlayerPrefs.Save();

                            request = null;
                        }
                        else
                            status = "Processing";
                    }
                    else
                    {
                        status = string.Format("Request finished Successfully, but the server sent an error. Status Code: {0}-{1} Message: {2}",
                                                        resp.StatusCode,
                                                        resp.Message,
                                                        resp.DataAsText);
                        Debug.LogWarning(status);

                        request = null;
                    }
                    break;

                // The request finished with an unexpected error. The request's Exception property may contain more info about the error.
                case HTTPRequestStates.Error:
                    status = "Request Finished with Error! " + (req.Exception != null ? (req.Exception.Message + "\n" + req.Exception.StackTrace) : "No Exception");
                    Debug.LogError(status);

                    request = null;
                    break;

                // The request aborted, initiated by the user.
                case HTTPRequestStates.Aborted:
                    status = "Request Aborted!";
                    Debug.LogWarning(status);

                    request = null;
                    break;

                // Ceonnecting to the server is timed out.
                case HTTPRequestStates.ConnectionTimedOut:
                    status = "Connection Timed Out!";
                    Debug.LogError(status);

                    request = null;
                    break;

                // The request didn't finished in the given time.
                case HTTPRequestStates.TimedOut:
                    status = "Processing the request Timed Out!";
                    Debug.LogError(status);

                    request = null;
                    break;
            }
        });

        // Are there any progress, that we can continue?
        if (PlayerPrefs.HasKey("DownloadProgress"))
            // Set the range header
            request.SetRangeHeader(PlayerPrefs.GetInt("DownloadProgress"));
        else
            // This is a new request
            PlayerPrefs.SetInt("DownloadProgress", 0);

        // If we are writing our own file set it true(disable), so don't duplicate it on the filesystem
        request.DisableCache = true;

        // We want to access the downloaded bytes while we are still downloading
        request.UseStreaming = true;

        // Set a reasonable high fragment size. Here it is 5 megabytes.
        request.StreamFragmentSize = fragmentSize;

        // Start Processing the request
        request.Send();
    }

    /// <summary>
    /// In this function we can do whatever we want with the downloaded bytes. In this sample we will do nothing, just set the metadata to display progress.
    /// </summary>
    void ProcessFragments(List<byte[]> fragments)
    {
        if (fragments != null && fragments.Count > 0)
        {
            /*string dir = "TODO!";
            string filename = "TODO!";

            using (System.IO.FileStream fs = new System.IO.FileStream(System.IO.Path.Combine(dir, filename), System.IO.FileMode.Append))
                for (int i = 0; i < fragments.Count; ++i)
                    fs.Write(fragments[i], 0, fragments[i].Length);*/

            for (int i = 0; i < fragments.Count; ++i)
            {
                // Save how many bytes we wrote successfully
                int downloaded = PlayerPrefs.GetInt("DownloadProgress") + fragments[i].Length;
                PlayerPrefs.SetInt("DownloadProgress", downloaded);
            }

            PlayerPrefs.Save();

            // Set the progress to the actually processed bytes
            progress = PlayerPrefs.GetInt("DownloadProgress") / (float)PlayerPrefs.GetInt("DownloadLength");
        }
    }

    #endregion
}
